﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace gpuimp.core
{
    [Serializable]
    public class StateManager
    {
        private int maxNumberOfState;
        private int position;
        private int nextID;
        private int canvasID;
        private List<State> theStateList;
        State oldState;

        //constructor
        public StateManager(int cID)
        {
            theStateList = new List<State>();
            maxNumberOfState = 50;
            position = 0;
            canvasID = cID;
        }

        public List<State> getStates
        {
            get { return theStateList; }
        }

        /// <summary>
        /// Adds a state to the list of States.  Actoins Performed:
        /// Creating a new state from the given parameters.
        /// Adding the new state to the list of states.
        /// </summary>
        /// <param name="layer">Layer object that we're adding</param>
        /// <param name="actionPerformed">Name of the Action Performed, normally the Tool</param>
        public void addState(Layer layer, string actionPerformed)
        {
            try
            {
                //if we're below the max number of states, simply add the state on
                if (theStateList.Count < maxNumberOfState)
                {
                    try
                    {
                        //copy the layer data
                        Layer newLayer = (Layer)layer.Clone();

                        //if we're not at the most recent part of the stack, then we'll have to do a little restructuring
                        if (position != theStateList.Count - 1 && theStateList.Count > 0)
                        {
                            List<State> newList = theStateList.GetRange(0, position + 1);


                            //then we trim
                            newList.Add(new State(newLayer, actionPerformed, nextID));

                            theStateList = newList;

                            Console.WriteLine(theStateList[1].GetHashCode() + "  " + theStateList[2].GetHashCode());
                            
                        }
                        else //if we're on the head of the stack, just add the layer to the end
                        {
                            theStateList.Add(new State(newLayer, actionPerformed, nextID));
                        }

                        oldState = theStateList[position];
                        nextID++;

                        //adding a new state will make the position equal to the newest state added to the list
                        position = theStateList.Count - 1;

                        Console.WriteLine("Added State, Position " + position);
                    }
                    catch (NullReferenceException nre)
                    {
                        Console.WriteLine(nre.Message);
                    } 
                }
                else
                {
                    //if theStateList is full, we need to remove the oldest state to add on a new state.
                    theStateList.Remove(theStateList[0]);

                    Layer newLayer = (Layer)layer.Clone();

                    theStateList.Add(new State(newLayer, actionPerformed, nextID));
                    nextID++;

                }

            }
            catch (Exception se)
            {
                Console.WriteLine(se.Message);
            }
        }

        /// <summary>
        /// Returns the layer of the previous state.
        /// </summary>
        /// <returns>Layer object pertaining to the previous state.</returns>
        public void undo()
        {
            try
            {
                if (position >= 0)        ///not empty
                {
                    int i = 0;
                    int canvasPosition = -1;
                    int foundPosition = -1;

                    //get the canvasPosition
                    CanvasManager.Canvases.ForEach(delegate(Canvas c)
                    {
                        if (c.ID == canvasID)
                        {
                            canvasPosition = i;
                        }

                        i++;
                    });

                    i = 0;

                    //if we found our canvas and the state list is not empty
                    if (canvasPosition >= 0 && theStateList.Count > 0)
                    {
                        //we find the layer's position
                        CanvasManager.getCanvas(canvasPosition).LayerManager.Layers.ForEach(delegate(Layer l)
                        {
                            if (l.ID == theStateList[position].getLayer().ID)
                            {
                                foundPosition = i;
                            }

                            i++;
                        });
                    }

                    //if we found the layer
                    if (foundPosition >= 0)
                    {
                        //check to make sure the position is in bounds
                        if (position < theStateList.Count && position > 0)
                        {
                            position--;
                            
                            CanvasManager.getCanvas(canvasID).LayerManager.Layers[foundPosition] = (Layer)theStateList[position].getLayer().Clone();

                            Console.WriteLine("Undo, returning state: " + position);

                        }
                        
                    }
 
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }
        }

        /// <summary>
        /// Redo is similiar to Undo, but instead goes "forward" in the list.
        /// If we are already at the end of the list (i.e. most recent state), return null.
        /// </summary>
        /// <returns>The Layer that is being restored.</returns>
        public void redo()
        {
            try
            {
                //go to a more recent state (incrementing position)
                //if we are at the most recent position, we can't go further.
                if (theStateList.Count >= 1 && position < theStateList.Count - 1)
                {
                    //if the list isn't full
                    if (position < maxNumberOfState)
                    {
                        int i = 0;
                        int canvasPosition = -1;
                        int foundPosition = -1;

                        //find the canvas position
                        CanvasManager.Canvases.ForEach(delegate(Canvas c)
                        {
                            if (c.ID == canvasID)
                            {
                                canvasPosition = i;
                            }

                            i++;
                        });

                        i = 0;

                        //if we found the canvas position, and the position is not at the head
                        if (canvasPosition >= 0 && theStateList.Count >= 0 && position < theStateList.Count - 1)
                        {
                            //find the layer position
                            CanvasManager.getCanvas(canvasPosition).LayerManager.Layers.ForEach(delegate(Layer l)
                            {
                                if (l.ID == theStateList[position + 1].getLayer().ID)
                                {
                                    foundPosition = i;
                                }

                                i++;
                            });
                        }

                        //if we found the layer position
                        if (foundPosition >= 0)
                        {
                            //if we're not at the head of the stack
                            if (position < theStateList.Count - 1)
                            {
                                position++;

                                CanvasManager.getCanvas(canvasID).LayerManager.Layers[foundPosition] = (Layer)theStateList[position].getLayer().Clone();

                                Console.WriteLine("Redo, returning state: " + position);
                            }

                        }

                    }

                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

        }

        /// <summary>
        /// see if we're at the head of the stack
        /// </summary>
        /// <returns>true if we're at the head of the stack, false if not</returns>
        public bool isHead()
        {
            if (position < theStateList.Count - 1)
            {
                return false;
            }

            return true;
        }

        //clear the list
        public void CleanUp()
        {
            theStateList.Clear();
        }
    }
}